package com.example.BlockChain.component;

import com.example.BlockChain.dao.TBlockDao;
import com.example.BlockChain.dao.TChainDataDao;
import com.example.BlockChain.entity.NoticeParams;
import com.example.BlockChain.entity.TradeBodyPool;
import com.example.BlockChain.entity.TradeObject;
import com.example.BlockChain.entity.block.BlockDownLoad;
import com.example.BlockChain.entity.block.BlockInfo;
import com.example.BlockChain.utils.BlockBaseUtils;
import com.example.BlockChain.utils.http.HttpHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component // 声明为一个 Spring 管理的组件
public class UpdateBlockTask {

    @Value("${node.ip}") // 通过配置文件读取节点的 IP 地址
    private String ip;

    @Resource // 自动注入 DAO 层（数据库访问）
    private TBlockDao tBlockDao;

    @Resource // 自动注入 DAO 层（数据库访问）
    private TChainDataDao tChainDataDao;

    /**
     * 定时任务，按照 cron 表达式定义每隔 5 秒执行一次。
     * 功能：检查并下载下一个区块，并更新区块链相关数据。
     */
    @Scheduled(cron = "*/5 * * * * ?") // 每隔 5 秒执行一次
    public void update() throws Exception {
        // 获取当前区块链的最新区块信息
        BlockInfo blockInfo = tBlockDao.queryBlockInfo();

        // 计算下一个区块的索引
        String nextIndex = String.valueOf(Integer.valueOf(blockInfo.getCurrentBlockIndex()) + 1);

        // 打印日志，说明正在下载哪个区块
        System.out.println("执行定时任务下载区块--------下载区块为：" + nextIndex);

        // 调用方法更新区块数据
        updateBlock(nextIndex);
    }

    /**
     * 功能：下载指定区块，并将区块中的交易数据同步到数据库。
     * @param blockIndex 区块索引
     */
    public void updateBlock(String blockIndex) throws Exception {
        BlockDownLoad bdl = null;

        // 创建通知参数对象，用于与外部服务交互
        NoticeParams np = new NoticeParams(blockIndex.toString(), ip, "");

        // 调用工具类，通过 HTTP 下载区块及其内容
        bdl = HttpHelper.downLoadBlock(ip, 8001, np);

        // 如果下载的区块为空，或者区块索引小于指定索引，则直接返回
        if (bdl == null || bdl.getBlock() == null ||
                Integer.valueOf(bdl.getBlock().blockIndex) < Integer.valueOf(blockIndex)) {
            return;
        }

        // 解析下载的区块数据，生成交易池对象
        TradeBodyPool tbp = BlockBaseUtils.genTbp(bdl);

        // 用于存储交易对象
        List<TradeObject> list = new ArrayList<>();

        // 将交易池中的交易对象提取到列表中
        Map<String, TradeObject> tbMap = tbp.getTbMap();
        for (Map.Entry<String, TradeObject> entry : tbMap.entrySet()) {
            TradeObject tradeObject = entry.getValue();
            list.add(tradeObject);
        }

        // 遍历交易列表，将每笔交易的数据同步到数据库
        for (TradeObject tradeObject : list) {
            tradeObject.setBlockIndex(blockIndex); // 设置区块索引
            tChainDataDao.updateData(tradeObject); // 更新交易数据到数据库
        }

        // 创建新的区块信息对象
        BlockInfo blockInfo = new BlockInfo();
        blockInfo.setBlockIndex(bdl.getMaxBlockIndex()); // 设置区块的最大索引
        blockInfo.setCurrentBlockIndex(String.valueOf(Integer.valueOf(blockIndex))); // 设置当前区块索引

        // 更新数据库中的区块链状态
        tBlockDao.updateBlock(blockInfo);

        // 打印日志说明更新完成
        System.out.println("更新完成-------");
    }
}
